module aru_mux_1_to_4_top (
    input logic              clk,
    input logic              rst_n,
          aru_mux_cfg_if.in  u_cfg_if,
          aru_payload_if.in  u_pld_in_if,
          aru_payload_if.out u_pld_out0_if,
          aru_payload_if.out u_pld_out1_if,
          aru_payload_if.out u_pld_out2_if,
          aru_payload_if.out u_pld_out3_if
);

    logic     cfg_vld;
    logic     cfg_rdy;
    logic     last_req_in_instr;

    aru_dat_t dat_d1;
    aru_sdb_t sdb_d1;

    logic     has_data;
    logic up_vld, up_rdy, down_vld, down_rdy;

    assign last_req_in_instr = sdb_d1.eom && sdb_d1.eon;

    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            cfg_rdy <= 1'b1;
        end else if (cfg_rdy == 1'b0) begin
            if (last_req_in_instr && down_vld && down_rdy) begin
                cfg_rdy <= 1'b1;
            end
        end else begin
            if (u_cfg_if.vld && u_cfg_if.rdy) begin
                cfg_rdy <= 1'b0;
            end
        end
    end

    assign u_cfg_if.rdy = cfg_rdy;

    always_comb begin
        case (u_cfg_if.mode)
            2'b00:   down_rdy = u_pld_out0_if.rdy;
            2'b01:   down_rdy = u_pld_out1_if.rdy;
            2'b10:   down_rdy = u_pld_out2_if.rdy;
            2'b11:   down_rdy = u_pld_out3_if.rdy;
            default: down_rdy = 1'b0;
        endcase
    end

    assign up_vld = u_pld_in_if.vld;
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            has_data <= 1'd0;
        end else if (has_data) begin
            if (~up_vld && down_rdy) begin
                has_data <= 1'd0;
            end
        end else begin
            if (up_vld) begin
                has_data <= 1'd1;
            end
        end
    end
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            dat_d1 <= '0;
            sdb_d1 <= '0;
        end else if (u_pld_in_if.vld && u_pld_in_if.rdy) begin
            dat_d1 <= u_pld_in_if.dat;
            sdb_d1 <= u_pld_in_if.sdb;
        end
    end
    assign down_vld          = has_data;
    assign up_rdy            = (~has_data) || down_rdy;

    assign cfg_vld           = ~cfg_rdy;
    assign u_pld_out0_if.vld = cfg_vld && down_vld && (u_cfg_if.mode == 2'b00);
    assign u_pld_out1_if.vld = cfg_vld && down_vld && (u_cfg_if.mode == 2'b01);
    assign u_pld_out2_if.vld = cfg_vld && down_vld && (u_cfg_if.mode == 2'b10);
    assign u_pld_out3_if.vld = cfg_vld && down_vld && (u_cfg_if.mode == 2'b11);
    assign u_pld_out0_if.dat = dat_d1;
    assign u_pld_out0_if.sdb = sdb_d1;
    assign u_pld_out1_if.dat = dat_d1;
    assign u_pld_out1_if.sdb = sdb_d1;
    assign u_pld_out2_if.dat = dat_d1;
    assign u_pld_out2_if.sdb = sdb_d1;
    assign u_pld_out3_if.dat = dat_d1;
    assign u_pld_out3_if.sdb = sdb_d1;
    assign u_pld_in_if.rdy   = up_rdy && cfg_vld;

endmodule
